﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using YArchitech.Revit;
using HYRevitCode.ElementSearchUtility.LinkDocumentSuite;
using HYRevitCode.GeometryUtility;
using YJKRGeometry;

namespace AdjustInstallationHeight
{
	internal class BeamAndFloorSearcher
	{
		public List<BeamAndFloorStructure> LstFloor
		{
			get
			{
				return this.m_lstFloor;
			}
			set
			{
				this.m_lstFloor = value;
			}
		}

		public List<BeamAndFloorStructure> LstBeam
		{
			get
			{
				return this.m_lstBeam;
			}
			set
			{
				this.m_lstBeam = value;
			}
		}

		public BeamAndFloorSearcher(Document doc)
		{
			this.LstFloor = this.GetBeamOrFloorList(doc, this.LstFloor, BuiltInCategory.OST_Floors);
			this.LstBeam = this.GetBeamOrFloorList(doc, this.LstBeam, BuiltInCategory.OST_StructuralFraming);
			this.LstFloor = (from k in this.LstFloor
			orderby k.m_dLevel descending
			select k).ToList<BeamAndFloorStructure>();
			this.LstBeam = (from k in this.LstBeam
			orderby k.m_dLevel descending
			select k).ToList<BeamAndFloorStructure>();
		}

		private List<BeamAndFloorStructure> GetBeamOrFloorList(Document doc, List<BeamAndFloorStructure> lstBeamAndFloor, BuiltInCategory builtInCategory)
		{
			FilteredElementCollectorLinkDocument filteredElementCollectorLinkDocument = new FilteredElementCollectorLinkDocument(doc);
			BeamAndFloorStructure beamAndFloorStructure = new BeamAndFloorStructure();
			List<BeamAndFloorInfo> list = new List<BeamAndFloorInfo>();
			BeamAndFloorInfo beamAndFloorInfo = new BeamAndFloorInfo();
			foreach (BaseLinkDocumentResultBean baseLinkDocumentResultBean in filteredElementCollectorLinkDocument.OfCategory(builtInCategory).WhereElementIsNotElementType().ToBeans())
			{
				beamAndFloorStructure = new BeamAndFloorStructure();
				beamAndFloorInfo = new BeamAndFloorInfo();
				list = new List<BeamAndFloorInfo>();
				Level level;
                if ((int)builtInCategory == -2000032)
				{
					level = (baseLinkDocumentResultBean.UseElement.Document.GetElement(baseLinkDocumentResultBean.UseElement.LevelId) as Level);
				}
				else
				{
					level = (baseLinkDocumentResultBean.UseElement.Document.GetElement(baseLinkDocumentResultBean.UseElement.GetParameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM).AsElementId()) as Level);
				}
				if (level != null)
				{
					if (baseLinkDocumentResultBean.UseLinkeInstance != null)
					{
						beamAndFloorStructure.m_dLevel = level.Elevation + LinkDocumentUtility.CalculateTransformEffectOnZ(baseLinkDocumentResultBean.UseLinkeInstance.GetTotalTransform());
					}
					else
					{
						beamAndFloorStructure.m_dLevel = level.Elevation;
					}
					beamAndFloorInfo.m_LinkInstance = baseLinkDocumentResultBean.UseLinkeInstance;
					if (baseLinkDocumentResultBean.UseLinkeInstance != null)
					{
						beamAndFloorInfo.m_face = this.GetLowerFace(baseLinkDocumentResultBean.UseElement, baseLinkDocumentResultBean.UseLinkeInstance.GetTotalTransform());
						PlanarFace planarFace = beamAndFloorInfo.m_face as PlanarFace;
						if (planarFace == null)
						{
							continue;
						}
						beamAndFloorStructure.m_dLevel = planarFace.Origin.Z + LinkDocumentUtility.CalculateTransformEffectOnZ(baseLinkDocumentResultBean.UseLinkeInstance.GetTotalTransform());
					}
					else
					{
						beamAndFloorInfo.m_face = this.GetLowerFace(baseLinkDocumentResultBean.UseElement, null);
						PlanarFace planarFace = beamAndFloorInfo.m_face as PlanarFace;
						if (planarFace == null)
						{
							continue;
						}
						beamAndFloorStructure.m_dLevel = planarFace.Origin.Z;
					}
					beamAndFloorInfo.m_id = baseLinkDocumentResultBean.UseElement.Id;
					beamAndFloorInfo.m_name = baseLinkDocumentResultBean.UseElement.Category.Id.IntegerValue;
					list.Add(beamAndFloorInfo);
					beamAndFloorStructure.m_lstFaceInfo = list;
					bool flag = true;
					for (int i = 0; i < lstBeamAndFloor.Count; i++)
					{
						if (Geometry.IsEqual(lstBeamAndFloor[i].m_dLevel, beamAndFloorStructure.m_dLevel))
						{
							flag = false;
							lstBeamAndFloor[i].m_lstFaceInfo.Add(beamAndFloorInfo);
						}
					}
					if (flag)
					{
						lstBeamAndFloor.Add(beamAndFloorStructure);
					}
				}
			}
			return lstBeamAndFloor;
		}

		private Face GetLowerFace(Element element, Transform transform)
		{
			Face result = null;
			List<PlanarFace> list = new List<PlanarFace>();
			Options options = new Options();
			options.ComputeReferences = true;
			new YJKElement(element);
			foreach (Solid solid in GeometryUtilityMethod.GetAllSolid(element.get_Geometry(options), transform))
			{
				list.Add(BeamAndFloorSearcher.GetSolidFace(solid));
			}
			list = (from n in list
			where null != n
			select n).ToList<PlanarFace>();
			list = (from k in list
			orderby k.Origin.Z
			select k).ToList<PlanarFace>();
			if (list.Count > 0)
			{
				result = list[0];
			}
			return result;
		}

		private static PlanarFace GetSolidFace(Solid solid)
		{
			PlanarFace result = null;
			foreach (object obj in solid.Faces)
			{
				PlanarFace planarFace = obj as PlanarFace;
				if (planarFace != null && planarFace.FaceNormal().Z < 0.0)
				{
					result = planarFace;
				}
			}
			return result;
		}

		private Face CreatBeamFace(Element element)
		{
			return null;
		}

		private List<BeamAndFloorStructure> m_lstFloor = new List<BeamAndFloorStructure>();

		private List<BeamAndFloorStructure> m_lstBeam = new List<BeamAndFloorStructure>();
	}
}
